package com.daquexian.flexiblerichtextview;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.support.v4.content.ContextCompat;
import android.text.Html;
import android.text.Layout;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.AlignmentSpan;
import android.text.style.BackgroundColorSpan;
import android.text.style.BulletSpan;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.ImageSpan;
import android.text.style.LeadingMarginSpan;
import android.text.style.RelativeSizeSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan;
import android.text.style.SubscriptSpan;
import android.text.style.SuperscriptSpan;
import android.text.style.UnderlineSpan;
import android.util.AttributeSet;
import android.util.Base64;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TableLayout;
import android.widget.TableRow;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.target.Target;
import com.daquexian.flexiblerichtextview.greendao.bean.FlexiImg;
import com.daquexian.flexiblerichtextview.greendao.dao.FlexiImgDao;
import com.daquexian.flexiblerichtextview.greendao.help.DaoManager;
import com.daquexian.flexiblerichtextview.span.MarkemphasisSpan;
import com.daquexian.flexiblerichtextview.span.WavyLineSpan;
import com.geek.thread.GeekThreadPools;
import com.pixplicity.sharp.Drawable2Bitmap;
import com.pixplicity.sharp.Sharp;
import com.pixplicity.sharp.SharpDrawable;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import io.github.kbiakov.codeview.CodeView;

import static com.daquexian.flexiblerichtextview.Tokenizer.*;

/**
 * Created by jianhao on 16-8-26.
 */
public class FlexibleRichTextView extends LinearLayout {
    private final static String TAG = "FlexibleRichTextView";
    private final static int HANDLER_IS_TABLE = 1;
    private final static int HANDLER_LOAD_COMPLETE = 2;
    public static long load_time = 0;

    private static int flexibleRichId = 0;
    private ArrayList<Integer> flexibleRichIdArr = new ArrayList<>();

    private float latexSizeScale = MyConfige.latexSizeScale;

    private boolean isMovementMethod = false;  //是否设置每个TextView内部能够上下滚动 2020-04-27

    static final int MAX_IMAGE_WIDTH = (int) (Resources.getSystem().getDisplayMetrics().widthPixels * 0.8);

    private Context mContext;
    @SuppressWarnings({"unused", "FieldCanBeLocal"})
    private int mConversationId;
    private List<Attachment> mAttachmentList;
    private OnViewClickListener mOnViewClickListener;

    private List<Tokenizer.TOKEN> mTokenList;
    private int mTokenIndex;

    private boolean mCenter;

    private boolean mShowRemainingAtt = true;

    private int mQuoteViewId = R.layout.default_quote_view;

    private int     td_group_count = 0;   //所有单元格的个数
    private boolean isHaveTable = false;  //是否有表格数据
    private String text_deleteTable_pre = "";//删除表格数据前备份,
    private boolean is_table_after_mode = true;  //是否是表格后加载模式，因为表格加载特别费时间，后加载模式会加快界面的显示速度

    private boolean isHaveImg = false;
    private boolean b_second_line_img = true; //防止死循环
    private String text_back = ""; //为了第二次解析，图片到一行

    private int en_unline_num = 0; //英语里面填空题，数字

    private static final int ENTER_TEXT_TYPE_FIRST = 1; //去除表格第一次刷新数据
    private static final int ENTER_TEXT_TYPE_HAVETABLE_FIRST = 2; //加上表格第一次刷新数据
    private static final int ENTER_TEXT_TYPE_HAVETABLE_CELL = 3; //加上表格后每次刷新单元格数据
    private static final int ENTER_TEXT_TYPE_HAVEIMG_FIRST = 4; //有图片，第一次刷新

    FlexiImgDao flexiImgDao = null;
    private volatile boolean isKill = false;

    Pattern pt_table = null;
    Matcher mt_table = null;
    Pattern pt_tr = null;
    Matcher mt_tr = null;
    Pattern pt_td = null;
    Matcher mt_td = null;
    Pattern pt_p = null;
    Matcher mt_p = null;
    Pattern pt_p_rn = null;
    Matcher mt_p_rn = null;
    Pattern pt_svg = null;
    Matcher mt_svg = null;
    Pattern pt_base64 = null;
    Matcher mt_base64 = null;
    Pattern pt_img = null;
    Matcher mt_img = null;
    Pattern pt_td_group_count = null;
    Matcher mt_td_group_count = null;
    Pattern pt_ifHaveTableDelete = null;
    Matcher mt_ifHaveTableDelete = null;
    Pattern pt_ifFirstDeleteImg = null;
    Matcher mt_ifFirstDeleteImg = null;
    Pattern pt_table_2 = null;
    Matcher mt_table_2 = null;
    Pattern pt_line_img_find_src = null;
    Matcher mt_line_img_find_src = null;
    Pattern pt_line_img_pattern_src = null;
    Matcher mt_line_img_pattern_src = null;
    Pattern pt_latex_zh_2 = null;
    Matcher mt_latex_zh_2 = null;
    Pattern pt_latex_zh_3 = null;
    Matcher mt_latex_zh_3 = null;




    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch(msg.what){
                case HANDLER_IS_TABLE:{
                    int flexId = msg.arg1;
                    if(text_deleteTable_pre != null && !"".equals(text_deleteTable_pre.trim()) && flexibleRichIdArr.contains(flexId)) {
                        setText(text_deleteTable_pre, new ArrayList<Attachment>(), ENTER_TEXT_TYPE_HAVETABLE_FIRST, td_group_count, isHaveTable, text_deleteTable_pre);
                    }
                }break;
                case HANDLER_LOAD_COMPLETE:{
                    //Log.i(TAG, "------------------------>>>>>>>>>7-0");
                    if(listener != null) {
                        //Log.i(TAG, "------------------------>>>>>>>>>7");
                        Log.e(TAG, "加载数据花费的时间：" + (System.currentTimeMillis() - load_time));
                        listener.onComplete(FlexibleRichTextView.this);
                    }
                }break;
            }
        }
    };

    public FlexibleRichTextView(Context context) {
        this(context, null, true);

    }

    @SuppressWarnings("unused")
    public FlexibleRichTextView(Context context, OnViewClickListener onViewClickListener) {
        this(context, onViewClickListener, true);
    }

    @SuppressWarnings("unused")
    public FlexibleRichTextView(Context context, OnViewClickListener onViewClickListener, boolean showRemainingAtt) {
        super(context);
        init(context, onViewClickListener, showRemainingAtt);
    }

    public FlexibleRichTextView(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
        init(context);
    }

    public FlexibleRichTextView(Context context, AttributeSet attributeSet, int defStyleAttr) {
        super(context, attributeSet, defStyleAttr);
        init(context);
    }

    public void setToken(List<TOKEN> tokens, List<Attachment> attachmentList) {
        removeAllViews();

        mAttachmentList = attachmentList;
        mTokenList = tokens;

        for (TOKEN token : tokens) {
            if (token instanceof ATTACHMENT) {
                mAttachmentList.remove(((ATTACHMENT) token).attachment);
            }
        }

        resetTokenIndex();
        List<Object> result = until(END.class);

        if (mShowRemainingAtt) {
            // remaining attachments will show at the bottom of view
            for (Attachment att : mAttachmentList) {
                append(result, attachment(att));
            }
        }

        if (result == null) {
            return;
        }

        for (final Object o : result) {
            if (o instanceof TextWithFormula) {
                final TextWithFormula textWithFormula = (TextWithFormula) o;

                final LaTeXtView textView = new LaTeXtView(mContext);
                textView.setLineSpacing(MyConfige.lineSpacingExtra, MyConfige.lineSpacingMultiplier);

                textView.setTextWithFormula(textWithFormula, latexSizeScale);
                if(isMovementMethod) {
                    textView.setMovementMethod(LinkMovementMethod.getInstance());
                }
                myAddView(textView);
            } else if (o instanceof CodeView) {
                myAddView((CodeView) o);
            } else if (o instanceof ImageView) {
                myAddView((ImageView) o);
            } else if (o instanceof HorizontalScrollView) {
                myAddView((HorizontalScrollView) o);
            } else if (o instanceof QuoteView) {
                myAddView((QuoteView) o);
            }
        }
    }

    public void setLatexSizeScale(float scale) {
        latexSizeScale = scale;
    }

    public void setIsMovementMethod(boolean isMovementMethod) {
        this.isMovementMethod = isMovementMethod;
    }
    public void resetTextView() {
        en_unline_num = 0;
        b_second_line_img = true;
        flexibleRichIdArr = new ArrayList<>();

        //2020-08-21
        td_group_count = 0;
        isHaveTable = false;
        text_deleteTable_pre = "";
        isHaveImg = false;

        //2020-09-01 注释掉的，demo显示没有问题，但深圳兼容进去本地图片显示不了，
        //=true，是为了解决频繁切题时，将上一题的线程及时停止掉。
        //isKill = true;

    }

    public void set_b_second_line_img(boolean b) {
        b_second_line_img = b;
    }

    public void setText(String text) {
        //2020-09-01 注释掉的，demo显示没有问题，但深圳兼容进去本地图片显示不了，
        //=true，是为了解决频繁切题时，将上一题的线程及时停止掉。
        //isKill = false;
        Log.e(TAG, "加载数据花费的时间：0");
        FlexibleRichTextView.flexibleRichId++;
        flexibleRichIdArr.add(FlexibleRichTextView.flexibleRichId);
        td_group_count = 0;
        isHaveTable = false;
        text_deleteTable_pre = "";
        text = pattern_svg(text);
        text = pattern_base64(text);
        text = pattern_common(text);
        text = pattern_latex(text);
        text = pattern_span(text);
        text_back = text;
        //Log.i(TAG, "------------------------>>>>>>>>>-1");
        setText(text, new ArrayList<Attachment>(), ENTER_TEXT_TYPE_FIRST, td_group_count, isHaveTable, text_deleteTable_pre);
    }

    public void setText(String text, List<Attachment> attachmentList, int type, int group_count, boolean haveTable, String deleteTable_pre) {
        //Log.i(TAG, "------------------------>>>>>>>>>0 type = " + type + ", group_count = " + group_count);
        this.td_group_count = group_count;
        this.isHaveTable = haveTable;
        this.text_deleteTable_pre = deleteTable_pre;
        if(type == ENTER_TEXT_TYPE_FIRST) {
            en_unline_num = 0;
            if(MyConfige.isNoFirstShowImg) {
                //Log.i(TAG, "------------------------>>>>>>>>>1");
                text = ifFirstDeleteImg(text);
            }
        }

        if(type == ENTER_TEXT_TYPE_HAVETABLE_FIRST || type == ENTER_TEXT_TYPE_HAVEIMG_FIRST) {
            en_unline_num = 0;
        }

        //type //第一次进来是p标签添加指定多个/r/n, 第一次添加表格数据指定多个/r/n, 刷新单元格数据只添加一个/r/n
        //因为表格会多次新建FlexibleRichTextView,导致加载时间比没有表格要多达10倍，所以第一次去除表格加载，第二次再加载全部数据
        if(!isHaveTable && "".equals(text_deleteTable_pre) && is_table_after_mode) {
            //Log.i(TAG, "------------------------>>>>>>>>>2");
            text = ifHaveTableDelete(text);

        }

        /*if(type == ENTER_TEXT_TYPE_HAVETABLE_CELL) {
            td_group_count--;
        }*/


        //函数调用有的顺序不能变，pattern_base64必须在pattern_img之前调用，pattern_p需要在pattern_table之前调用
        //text = text.replaceAll("∁", "\\$\\$ \\\\text{∁} \\$\\$");
        text = text.replaceAll("∁", "\\$\\$ ∁ \\$\\$");
        text = pattern_base64(text);
        text = pattern_en_unline_num(text);
        text = pattern_p(text, type);
        text = pattern_img(text);
        text = pattern_table(text);
        mAttachmentList = attachmentList;
        mTokenList = tokenizer(text, mAttachmentList);

        setToken(mTokenList, attachmentList);

        if(isHaveTable) {
            //Log.i(TAG, "------------------------>>>>>>>>>3");
            Log.e(TAG, "加载数据花费的时间：1");
            isHaveTable = false;

            int flexId = 0;
            if(flexibleRichIdArr.size() > 0) {
                flexId = flexibleRichIdArr.get(flexibleRichIdArr.size() - 1);
            }
            Message msg = Message.obtain();
            msg.what = HANDLER_IS_TABLE;
            msg.arg1 = flexId;
            handler.sendMessageDelayed(msg, 50);
        }

        if(td_group_count == 0 && !isHaveImg && type != ENTER_TEXT_TYPE_HAVETABLE_FIRST) {
            //Log.i(TAG, "------------------------>>>>>>>>>4 type = " + type);
            handler.sendEmptyMessageDelayed(HANDLER_LOAD_COMPLETE, 50);
        }

        if(MyConfige.is_img_2_base64 && b_second_line_img) {
            //Log.i(TAG, "------------------------>>>>>>>>>5");
            b_second_line_img = false;
            if(isHaveImg) {
                //Log.i(TAG, "------------------------>>>>>>>>>6");
                isHaveImg = false;
                second_line_img(text_back);
            }
        }


    }

    private void myAddView(View view) {
        view.setPadding(0, 5, 0, 5);
        if (view instanceof FImageView && ((FImageView) view).centered) {
            // TODO: 17-2-13 any more efficient way?
            RelativeLayout rl = new RelativeLayout(mContext);
            //rl.setPadding(0, 10, 0, 10);
            RelativeLayout.LayoutParams rlLp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
            rlLp.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
            rl.addView(view);
            rl.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            addView(rl);
        } else {
            addView(view);
        }
    }

    private void resetTokenIndex() {
        mTokenIndex = 0;
    }

    private final Class[] start = {CENTER_START.class, BOLD_START.class, ITALIC_START.class,
            UNDERLINE_START.class, DELETE_START.class, CURTAIN_START.class, TITLE_START.class,
            COLOR_START.class, URL_START.class, MARKEMPHASIS_START.class, SUPERSCRIPT_START.class,
            SUBSCRIPT_START.class, WAVYLINE_START.class/*, LATEX_START.class*/, SPANHTML_START.class,
            PHTML_START.class, BASE64_START.class, ESCAPE_START.class, SVGSHARP_START.class,
            AbsoluteSize_START.class, RelativeSize_START.class};

    private final Class[] end = {CENTER_END.class, BOLD_END.class, ITALIC_END.class,
            UNDERLINE_END.class, DELETE_END.class, CURTAIN_END.class, TITLE_END.class,
            COLOR_END.class, URL_END.class, MARKEMPHASIS_END.class, SUPERSCRIPT_END.class,
            SUBSCRIPT_END.class, WAVYLINE_END.class/*, LATEX_END.class*/, SPANHTML_END.class,
            PHTML_END.class, BASE64_END.class, ESCAPE_END.class, SVGSHARP_END.class,
            AbsoluteSize_END.class, RelativeSize_END.class, };

    private final String CENTER_OP = "center";
    private final String BOLD_OP = "bold";
    private final String ITALIC_OP = "italic";
    private final String UNDERLINE_OP = "underline";
    private final String DELETE_OP = "delete";
    private final String CURTAIN_OP = "curtain";
    private final String TITLE_OP = "title";
    private final String COLOR_OP = "color";
    private final String AbsoluteSize_OP = "absoluteSize";
    private final String RelativeSize_OP = "relativeSize";
    private final String URL_OP = "url";
    private final String MARKEMPHASIS_OP = "markemphasis";
    private final String SUPERSCRIPT_OP = "superscript";
    private final String SUBSCRIPT_OP = "subscript";
    private final String WAVYLINE_OP = "wavyline";
    private final String SPANHTML_OP = "spanhtml";
    private final String PHTML_OP = "phtml";
    private final String BASE64_OP = "base64";
    private final String ESCAPE_OP = "escape";
    private final String SVGSHARP_OP = "svgsharp";
    //private final String LATEX_OP = "latex";

    private final String[] operation = {CENTER_OP, BOLD_OP, ITALIC_OP, UNDERLINE_OP, DELETE_OP,
            CURTAIN_OP, TITLE_OP, COLOR_OP, URL_OP, MARKEMPHASIS_OP, SUPERSCRIPT_OP, SUBSCRIPT_OP,
            WAVYLINE_OP/*, LATEX_OP*/, SPANHTML_OP, PHTML_OP, BASE64_OP, ESCAPE_OP, SVGSHARP_OP,
            AbsoluteSize_OP, RelativeSize_OP};

    private <T extends TOKEN> List<Object> until(Class<T> endClass) {
        List<Object> ret = new ArrayList<>();

        while (!(thisToken() instanceof END) && !(endClass.isInstance(thisToken()))) {
            boolean flag = false;
            int tmp;

            for (Class anEnd : end) {
                if (anEnd.isInstance(thisToken())) {
                    append(ret, new TextWithFormula(thisToken().value));
                    flag = true;
                    break;
                }
            }

            for (int i = 0; i < start.length; i++) {
                if (start[i].isInstance(thisToken())) {
                    /*String operand = "";
                    if (thisToken() instanceof CENTER_START) {
                        mCenter = true;
                    } else if (thisToken() instanceof COLOR_START) {
                        operand = ((COLOR_START) thisToken()).color;
                    } else if (thisToken() instanceof URL_START) {
                        operand = ((URL_START) thisToken()).url;
                    } else if(thisToken() instanceof PHTML_START) {
                        PHTML_START ss = (PHTML_START) thisToken();
                    }*/
                    TOKEN startToken = thisToken();

                    tmp = getTokenIndex();
                    next();
                    List<Object> shown = until(end[i]);
                    mCenter = false;
                    if (shown != null) {
                        concat(ret, operate(shown, operation[i], startToken));
                    } else {
                        setTokenIndex(tmp);
                        append(ret, new TextWithFormula(thisToken().value));
                    }
                    flag = true;
                }
            }

            if (!flag) {
                if (thisToken() instanceof PLAIN) {
                    /*String value = Html.fromHtml(thisToken().value.toString()).toString();
                    append(ret, new TextWithFormula(value));*/
                    append(ret, new TextWithFormula(thisToken().value));

                } else if (thisToken() instanceof ICON) {
                    final ICON thisToken = (ICON) thisToken();

                    TextWithFormula textWithFormula = new TextWithFormula(thisToken.value);
                    textWithFormula.setSpan(new ImageSpan(mContext, thisToken.iconId), 0,
                            thisToken.value.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

                    append(ret, textWithFormula);

                } else if (thisToken() instanceof FORMULA) {

                    FORMULA thisToken = (FORMULA) thisToken();
                    /*String value = pattern_latex_zh(thisToken().value.toString());
                    String content = pattern_latex_zh(thisToken.content);*/
                    String value = thisToken().value.toString();
                    String content = thisToken.content;
                    TextWithFormula textWithFormula = new TextWithFormula(value);

                    textWithFormula.addFormula(0, thisToken.value.length(),
                            content, thisToken.contentStart,
                            thisToken.contentStart + thisToken.content.length());

                    append(ret, textWithFormula);

                } else if (thisToken() instanceof CODE_START) {
                    /**
                     * [code][code][/code][/code][/code] shows [code][/code][/code]
                     */
                    tmp = getTokenIndex();
                    int i = 1;
                    StringBuilder string = new StringBuilder("");
                    StringBuilder substring = new StringBuilder("");
                    next();
                    while (!(thisToken() instanceof END)) {
                        if (thisToken() instanceof CODE_START) {
                            i++;
                        }
                        if (thisToken() instanceof CODE_END) {
                            i--;
                            if (i == 0) {
                                string.append(substring);
                                break;
                            }
                            string.append(substring);
                            substring.delete(0, substring.length());
                            tmp = getTokenIndex() + 1;
                        }
                        substring.append(thisToken().value);
                        next();
                    }

                    if (i == 0) {
                        final CodeView codeView = (CodeView) LayoutInflater.from(mContext).inflate(R.layout.code_view, this, false);
                        codeView.setCode(string.toString());
                        ret.add(codeView);
                    } else if (!TextUtils.isEmpty(string)) {
                        setTokenIndex(tmp);
                        final CodeView codeView = (CodeView) LayoutInflater.from(mContext).inflate(R.layout.code_view, this, false);
                        codeView.setCode(string.toString());
                        ret.add(codeView);
                    } else {
                        setTokenIndex(tmp);
                        append(ret, new TextWithFormula(thisToken().value));
                    }

                } else if (thisToken() instanceof IMAGE) {

                    IMAGE thisToken = (IMAGE) thisToken();
                    FImageView imageView = loadImage(thisToken.url, thisToken.width, thisToken.height);
                    if (mCenter) {
                        imageView.centered = true;
                    }
                    append(ret, imageView);

                } else if (thisToken() instanceof TABLE) {

                    //String strV = thisToken().value.toString();
                    //View table = table(thisToken().value);
                    View table = table_2(thisToken().value);
                    append(ret, table);

                } else if (thisToken() instanceof ATTACHMENT) {

                    final ATTACHMENT thisToken = (ATTACHMENT) thisToken();

                    append(ret, attachment(thisToken.attachment));

                } else if (thisToken() instanceof QUOTE_START) {
                    int i = 1;
                    List<TOKEN> tokens = new ArrayList<>();
                    next();
                    while (!(thisToken() instanceof END)) {
                        if (thisToken() instanceof QUOTE_START) {
                            i++;
                            while (i > 0) {
                                next();
                                if (thisToken() instanceof QUOTE_START) {
                                    i++;
                                } else if (thisToken() instanceof QUOTE_END) {
                                    i--;
                                }
                            }
                        } else if (thisToken() instanceof QUOTE_END) {
                            tokens.add(new END(thisToken().position));
                            break;
                        } else {
                            tokens.add(thisToken());
                        }
                        next();
                    }

                    if (thisToken() instanceof QUOTE_END) {
                        final QuoteView quoteView = QuoteView.newInstance(this, mQuoteViewId);
                        quoteView.setAttachmentList(mAttachmentList);
                        quoteView.setPadding(0, 8, 0, 8);
                        quoteView.setTokens(tokens);
                        quoteView.setOnButtonClickListener(mOnViewClickListener);
                        ret.add(quoteView);
                    } else {
                        append(ret, new TextWithFormula(thisToken().value));
                    }
                }
            }
            next();
        }

        if (endClass.isInstance(thisToken())) {
            return ret;
        }

        return null;
    }

    private Object attachment(final Attachment attachment) {
        if (attachment.isImage()) {
            String url = attachment.getUrl();
            FImageView imageView = loadImage(url);
            if (mCenter) {
                imageView.centered = true;
            }

            return imageView;
        } else {
            TextWithFormula builder = new TextWithFormula(attachment.getText());
            builder.setSpan(new ClickableSpan() {
                @Override
                public void onClick(View view) {
                    if (mOnViewClickListener != null) {
                        mOnViewClickListener.onAttClick(attachment);
                    }
                }
            }, 0, attachment.getText().length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
            builder.append("\n\n");

            return builder;
        }
    }
    private void append(List<Object> list, Object element) {
        concat(list, Collections.singletonList(element));
    }

    private FImageView loadImage(String url) {
        return loadImage(url, -1);
    }

    private FImageView loadImage(String url, int size) {
        return loadImage(url, size, size);
    }

    private FImageView loadImage(String url, int width, int height) {
        final FImageView imageView = new FImageView(mContext);

        ViewGroup.LayoutParams layoutParams;

        int phWidth, phHeight, imgWidth, imgHeight;

        if (height != -1 && width != -1) {
            imgHeight = height;
            imgWidth = width;
            phHeight = height;
            phWidth = width;
        } else if (width != -1) {
            imgHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
            imgWidth = width;
            phHeight = MAX_IMAGE_WIDTH / 2;
            phWidth = width;
        } else if (height != -1) {
            imgHeight = height;
            imgWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
            phHeight = height;
            phWidth = MAX_IMAGE_WIDTH;
        } else {
            imgHeight = imgWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
            phHeight = MAX_IMAGE_WIDTH / 2;
            phWidth = MAX_IMAGE_WIDTH;
        }
        if(imgWidth < MyConfige.img_scale_width_max && imgWidth > MyConfige.img_scale_width_min) {
            imgWidth = imgWidth * MyConfige.img_scale;
            imgHeight = imgHeight * MyConfige.img_scale;
        }
        if(phWidth < MyConfige.img_scale_width_max && phWidth > MyConfige.img_scale_width_min) {
            phWidth = phWidth * MyConfige.img_scale;
            phHeight = phHeight * MyConfige.img_scale;
        }

        if (imageView.centered) {
            layoutParams = new RelativeLayout.LayoutParams(phWidth, phHeight);
            ((RelativeLayout.LayoutParams) layoutParams).addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
        } else {
            layoutParams = new LinearLayout.LayoutParams(phWidth, phHeight);
        }
        imageView.setLayoutParams(layoutParams);
        imageView.setAdjustViewBounds(true);
        imageView.setPadding(0, 0, 0, 10);

        final int finalWidth = imgWidth;
        final int finalHeight = imgHeight;
        int flexId = 0;
        if(flexibleRichIdArr.size() > 0) {
            flexId = flexibleRichIdArr.get(flexibleRichIdArr.size() - 1);
        }
        final int f_flexId = flexId;
        if(FormatUtil.isInteger(url)) {
            Glide.with(mContext)
                    .load(Integer.parseInt(url))
                    .placeholder(new ColorDrawable(ContextCompat.getColor(mContext, android.R.color.darker_gray)))
                    .listener(new RequestListener<Integer, GlideDrawable>() {
                        @Override
                        public boolean onException(Exception e, Integer model, Target<GlideDrawable> target, boolean isFirstResource) {
                            Log.i(TAG, "试题图片-失败4");
                            return false;
                        }

                        @Override
                        public boolean onResourceReady(GlideDrawable resource, Integer model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                            /**
                             * adjust the size of ImageView according to image
                             */
                            if(flexibleRichIdArr.contains(f_flexId)) {
                                resourceReady(imageView, finalWidth, finalHeight, resource);
                            }
                            return false;
                        }
                    })
                    .into(imageView);
        } else {
            Glide.with(mContext)
                    .load(url)
                    .placeholder(new ColorDrawable(ContextCompat.getColor(mContext, android.R.color.darker_gray)))
                    .listener(new RequestListener<String, GlideDrawable>() {
                        @Override
                        public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
                            Log.i(TAG, "试题图片-失败3");
                            return false;
                        }

                        @Override
                        public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                            /**
                             * adjust the size of ImageView according to image
                             */
                            if(flexibleRichIdArr.contains(f_flexId)) {
                                resourceReady(imageView, finalWidth, finalHeight, resource);
                            }
                            return false;
                        }
                    })
                    .into(imageView);
        }
        return imageView;
    }

    private void resourceReady(final FImageView imageView, int finalWidth, int finalHeight, GlideDrawable resource) {
        if (imageView.centered) {
            final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(finalWidth, finalHeight);
            params.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
            imageView.setLayoutParams(params);
        } else {
            imageView.setLayoutParams(new LinearLayout.LayoutParams(finalWidth, finalHeight));
        }

        imageView.setImageDrawable(resource);

        imageView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                if (mOnViewClickListener != null) {
                    mOnViewClickListener.onImgClick(imageView);
                }
            }
        });
    }

    private List<Object> operate(List<Object> list, String operation, final Tokenizer.TOKEN token) {
        switch (operation) {
            case DELETE_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        textWithFormula.setSpan(new StrikethroughSpan(), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                    }
                }
                break;

            case CURTAIN_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        textWithFormula.setSpan(new BackgroundColorSpan(Color.DKGRAY), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                    }
                }
                break;
            case TITLE_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        textWithFormula.setSpan(new RelativeSizeSpan(1.3f), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                    }
                }
                break;
            case COLOR_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        try {
                            String operand = "#000000";
                            if (token instanceof COLOR_START) {
                                operand = ((COLOR_START) token).color;
                            }
                            int color = Color.parseColor(operand);
                            textWithFormula.setSpan(new ForegroundColorSpan(color), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                        } catch (IllegalArgumentException e) {
                            // avoid crash caused by illegal color
                        }
                    }
                }
                break;
            case AbsoluteSize_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        try {
                            String str_size = "0";
                            if (token instanceof AbsoluteSize_START) {
                                str_size = ((AbsoluteSize_START) token).size;
                            }
                            float f_size = Float.parseFloat(str_size);
                            textWithFormula.setSpan(new AbsoluteSizeSpan((int)f_size, false), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                        } catch (IllegalArgumentException e) {
                            // avoid crash caused by illegal color
                        }
                    }
                }
                break;
            case RelativeSize_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        try {
                            String str_size = "1";
                            if (token instanceof RelativeSize_START) {
                                str_size = ((RelativeSize_START) token).size;
                            }
                            float f_size = Float.parseFloat(str_size);
                            textWithFormula.setSpan(new RelativeSizeSpan(f_size), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                        } catch (IllegalArgumentException e) {
                            // avoid crash caused by illegal color
                        }
                    }
                }
                break;
            case URL_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        String operand = "";
                        if (token instanceof URL_START) {
                            operand = ((URL_START) token).url;
                        }
                        final String operand_2 = operand;
                        textWithFormula.setSpan(new ClickableSpan() {
                            @Override
                            public void onClick(View widget) {
                                mContext.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(operand_2)));
                            }
                        }, 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                    }
                }
                break;

            case CENTER_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        textWithFormula.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                    } else if (o instanceof ImageView) {
                        ((ImageView) o).setScaleType(ImageView.ScaleType.CENTER);
                    }
                }
                break;



            case BOLD_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        textWithFormula.setSpan(new StyleSpan(Typeface.BOLD), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                    }
                }
                break;

            case ITALIC_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        textWithFormula.setSpan(new StyleSpan(Typeface.ITALIC), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                    }
                }
                break;
            case UNDERLINE_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        textWithFormula.setSpan(new UnderlineSpan(), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                    }
                }
                break;
            case SVGSHARP_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        String str = textWithFormula.toString();
                        try {
                            str = URLDecoder.decode(str, "utf-8");
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                        int svg_start = str.indexOf("<svg");
                        int svg_end = str.indexOf("</svg>", svg_start);
                        str = str.substring(svg_start, svg_end + 6);
                        SharpDrawable sharpDrawable = Sharp.loadString(str).getDrawable();
                        Bitmap decodedByte = Drawable2Bitmap.DrawableToBitmap(sharpDrawable);
                        //Log.i(TAG, "111");
                        textWithFormula.replace(0, textWithFormula.length(), " ");
                        textWithFormula.setSpan(new ImageSpan(mContext, decodedByte, ImageSpan.ALIGN_BASELINE), 0, 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                        /*if (token instanceof BASE64_START) {
                            BASE64_START start = (BASE64_START)token;
                            String data = start.data.trim();
                            if(data != null && data.length() > 0) {
                                Bitmap decodedByte = Base64Util.base64ToBitmap(data);
                                textWithFormula.setSpan(new ImageSpan(mContext, decodedByte, ImageSpan.ALIGN_BASELINE), 0, 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                            }
                        }*/
                    }
                }
                break;
            case ESCAPE_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        String str = Html.fromHtml(textWithFormula.toString()).toString();
                        Log.i(TAG, "---转义字符---转换前:" + textWithFormula.toString() + "---转换后:" + str + "a");
                        textWithFormula.replace(0, textWithFormula.length(), str);
                    }
                }
                break;
            case MARKEMPHASIS_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        textWithFormula.setSpan(new MarkemphasisSpan(), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                    }
                }
                break;
            case SUPERSCRIPT_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        textWithFormula.setSpan(new SuperscriptSpan(), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                    }
                }
                break;
            case SUBSCRIPT_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        textWithFormula.setSpan(new SubscriptSpan(), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                    }
                }
                break;
            case WAVYLINE_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        textWithFormula.setSpan(new WavyLineSpan(getResources()), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                    }
                }
                break;
            case SPANHTML_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        //textWithFormula.setSpan(new UnderlineSpan(), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                    }
                }
                break;
            case PHTML_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        String text_align = "left";
                        String text_indent = "0";
                        if (token instanceof PHTML_START) {
                            PHTML_START start = (PHTML_START)token;
                            text_align = start.text_align.trim();
                            text_indent = start.text_indent.trim();
                        }
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        //textWithFormula.setSpan(new UnderlineSpan(), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                        if("center".equals(text_align)) {
                            textWithFormula.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                        } else if("right".equals(text_align)) {
                            textWithFormula.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_OPPOSITE), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                        }
                        try{
                            float indent = Float.parseFloat(text_indent);
                            if(indent > 0) {
                                textWithFormula.setSpan(new LeadingMarginSpan.Standard((int)((indent / 2) * MyConfige.s_f_text_indent), 0), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                            }
                        }catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
                break;
            case BASE64_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        if (token instanceof BASE64_START) {
                            BASE64_START start = (BASE64_START)token;
                            String data = start.data.trim();
                            if(data != null && data.length() > 1) {
                                Bitmap decodedByte = Base64Util.base64ToBitmap(data);
                                if(decodedByte != null) {
                                    //textWithFormula.setSpan(new ImageSpan(mContext, decodedByte, ImageSpan.ALIGN_BASELINE), 0, 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                                    textWithFormula.setSpan(new CenteredImageSpan(mContext, decodedByte), 0, 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                                }
                            }
                        }
                    }
                }
                break;
            /*case LATEX_OP:
                for (Object o : list) {
                    if (o instanceof TextWithFormula) {
                        final TextWithFormula textWithFormula = (TextWithFormula) o;
                        textWithFormula.setSpan(new UnderlineSpan(), 0, textWithFormula.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
                    }
                }
                break;*/


        }
        return list;
    }

    /*private List<Object> operate(List<Object> list, String operation) {
        return operate(list, operation, "");
    }*/

    private <T> void concat(List<Object> list1, List<T> list2) {
        if (list1.size() == 0) {
            list1.addAll(list2);
        } else {
            if (list2.size() > 0) {
                if (list1.get(list1.size() - 1) instanceof TextWithFormula &&
                        list2.get(0) instanceof TextWithFormula) {

                    TextWithFormula a = (TextWithFormula) list1.get(list1.size() - 1);
                    TextWithFormula b = (TextWithFormula) list2.get(0);
                    for (TextWithFormula.Formula formula : b.getFormulas()) {
                        formula.start += a.length();
                        formula.end += a.length();
                        formula.contentStart += a.length();
                        formula.contentEnd += a.length();
                    }
                    a.getFormulas().addAll(b.getFormulas());
                    a.append(b);

                    list1.addAll(list2.subList(1, list2.size()));
                } else {
                    list1.addAll(list2);
                }
            }
        }
    }

    private TOKEN thisToken() {
        return mTokenList.get(mTokenIndex);
    }

    private void next() {
        mTokenIndex++;
    }

    public int getTokenIndex() {
        return mTokenIndex;
    }

    public void setTokenIndex(int tokenIndex) {
        this.mTokenIndex = tokenIndex;
    }

    private View table(CharSequence str) {
        final String SPECIAL_CHAR = "\uF487";
        if(pt_table == null) {
            pt_table = Pattern.compile("(?:\\n|^)( *\\|.+\\| *\\n)??( *\\|(?: *:?----*:? *\\|)+ *\\n)((?: *\\|.+\\| *(?:\\n|$))+)");
        }
        mt_table = pt_table.matcher(str);
        int[] margins;
        final int LEFT = 0, RIGHT = 1, CENTER = 2;

        if (mt_table.find()) {

            List<String> headers = null;
            if (!TextUtils.isEmpty(mt_table.group(1))) {
                String wholeHeader = mt_table.group(1);

                headers = new ArrayList<>(Arrays.asList(wholeHeader.split("\\|")));
                format(headers);
            }

            List<String> partitions = new ArrayList<>(Arrays.asList(mt_table.group(2).split("\\|")));
            format(partitions);
            final int columnNum = partitions.size();
            margins = new int[columnNum];

            for (int i = 0; i < partitions.size(); i++) {
                String partition = partitions.get(i);
                if (partition.startsWith(":") && partition.endsWith(":")) {
                    margins[i] = CENTER;
                } else if (partition.startsWith(":")) {
                    margins[i] = LEFT;
                } else if (partition.endsWith(":")) {
                    margins[i] = RIGHT;
                } else {
                    margins[i] = CENTER;
                }
            }

            String[] rows = mt_table.group(3).replace("\\|", SPECIAL_CHAR).split("\n");
            final List<List<String>> content = new ArrayList<>();
            for (String row : rows) {
                content.add(format(new ArrayList<>(Arrays.asList(row.split("\\|")))));
            }

            final List<String[]> whole = new ArrayList<>();
            if (headers != null) {
                whole.add(headers.toArray(new String[columnNum]));
            }
            for (List<String> strings : content) {
                whole.add(strings.toArray(new String[columnNum]));
            }

            // render table
            HorizontalScrollView scrollView = new HorizontalScrollView(getContext());
            TableLayout tableLayout = new TableLayout(mContext);

            tableLayout.addView(getHorizontalDivider());
            for (int i = 0; i < whole.size(); i++) {
                String[] row = whole.get(i);
                TableRow tableRow = new TableRow(mContext);
                final TableLayout.LayoutParams params = new TableLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
                tableRow.setLayoutParams(params);

                tableRow.addView(getVerticalDivider());
                for (int j = 0; j < row.length; j++) {
                    String cell = row[j];
                    if (cell != null) {
                        cell = cell.replace(SPECIAL_CHAR, "|");
                    }
                    FlexibleRichTextView flexibleRichTextView = newInstance(getContext(), cell, mAttachmentList, mOnViewClickListener, false);
                    TableRow.LayoutParams pcvParams = new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT);
                    switch (margins[j]) {
                        case CENTER:
                            pcvParams.gravity = Gravity.CENTER;
                            break;
                        case LEFT:
                            pcvParams.gravity = Gravity.START;
                            break;
                        case RIGHT:
                            pcvParams.gravity = Gravity.END;
                            break;
                    }
                    flexibleRichTextView.setPadding(10, 10, 10, 10);
                    flexibleRichTextView.setLayoutParams(pcvParams);
                    tableRow.addView(flexibleRichTextView);
                    tableRow.addView(getVerticalDivider());
                }
                tableLayout.addView(tableRow);
                tableLayout.addView(getHorizontalDivider());
            }

            scrollView.addView(tableLayout);

            return scrollView;
        }

        return null;

    }

    private View table_2(CharSequence str) {
        final String SPECIAL_CHAR = "\uF487";
        //Log.i(TAG, str.toString());

        if(pt_tr == null) {
            pt_tr = Pattern.compile("<tr.*?>[\\s\\S]*?</tr>");
        }
        mt_tr = pt_tr.matcher(str);
        final List<List<String>> row_data = new ArrayList<>();
        final int LEFT = 0, RIGHT = 1, CENTER = 2;

        while (mt_tr.find()) {
            int tr_start = mt_tr.start();
            int tr_end = mt_tr.end();
            String tr_group = mt_tr.group();
            if(pt_td == null) {
                pt_td = Pattern.compile("<td.*?>[\\s\\S]*?</td>");
            }
            mt_td = pt_td.matcher(tr_group);
            List<String> col_data = new ArrayList<>();
            while(mt_td.find()) {
                int td_start = mt_td.start();
                int td_end = mt_td.end();
                String td_group = mt_td.group();
                String td_content = td_group.substring(td_group.indexOf(">") + 1, td_group.lastIndexOf("<"));
                td_content.replaceAll("<\\/?.+?\\/?>", "");
                col_data.add(td_content);
            }
            row_data.add(col_data);
        }

        if(row_data.size() > 0) {
            // render table
            HorizontalScrollView scrollView = new HorizontalScrollView(getContext());

            TableLayout tableLayout = new TableLayout(mContext);

            tableLayout.addView(getHorizontalDivider());
            for (List<String> row : row_data) {
                TableRow tableRow = new TableRow(mContext);
                final TableLayout.LayoutParams params = new TableLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
                tableRow.setLayoutParams(params);

                tableRow.addView(getVerticalDivider());
                for (String cell : row) {
                    if (cell != null) {
                        cell = cell.replace(SPECIAL_CHAR, "|");
                    }
                    Log.e(TAG, "加载数据花费的时间：2");
                    FlexibleRichTextView flexibleRichTextView = newInstance(getContext(), cell, mAttachmentList, mOnViewClickListener, false);
                    TableRow.LayoutParams pcvParams = new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT);
                    pcvParams.gravity = Gravity.CENTER;
                    flexibleRichTextView.setPadding(10, 10, 10, 10);
                    flexibleRichTextView.setLayoutParams(pcvParams);
                    tableRow.addView(flexibleRichTextView);
                    tableRow.addView(getVerticalDivider());
                }
                tableLayout.addView(tableRow);
                tableLayout.addView(getHorizontalDivider());
            }

            scrollView.addView(tableLayout);

            return scrollView;
        }
        return null;

    }


    private List<String> format(List<String> strings) {
        for (int i = strings.size() - 1; i >= 0; i--) {
            String str = strings.get(i);
            if (TextUtils.isEmpty(str) || str.equals("\n")) {
                strings.remove(i);
            }
        }

        for (int i = 0; i < strings.size(); i++) {
            strings.set(i, strings.get(i).trim());
        }

        return strings;
    }

    public FlexibleRichTextView newInstance(Context context, String string,
                                                   List<Attachment> attachmentList,
                                                   OnViewClickListener onViewClickListener,
                                                   boolean showRemainingAtt) {

        FlexibleRichTextView flexibleRichTextView = new FlexibleRichTextView(context, onViewClickListener, showRemainingAtt);
        flexibleRichTextView.set_b_second_line_img(false);
        flexibleRichTextView.setOnFlexibleListenerr(listener);
        if (!TextUtils.isEmpty(string)) {
            Log.e(TAG, "加载数据花费的时间：3");
            td_group_count--;
            flexibleRichTextView.setText(string, attachmentList, ENTER_TEXT_TYPE_HAVETABLE_CELL,td_group_count, isHaveTable, text_deleteTable_pre);
        } else {
            td_group_count--;
            if(td_group_count == 0) {
                handler.sendEmptyMessageDelayed(HANDLER_LOAD_COMPLETE, 50);
            }
        }

        return flexibleRichTextView;
    }

    private View getHorizontalDivider() {
        View horizontalDivider = new View(mContext);
        horizontalDivider.setLayoutParams(new TableLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
        horizontalDivider.setBackgroundColor(ContextCompat.getColor(mContext, android.R.color.black));

        return horizontalDivider;
    }

    private View getVerticalDivider() {
        View verticalDivider = new View(mContext);
        verticalDivider.setLayoutParams(new TableRow.LayoutParams(1, ViewGroup.LayoutParams.MATCH_PARENT));
        verticalDivider.setBackgroundColor(ContextCompat.getColor(mContext, android.R.color.black));

        return verticalDivider;
    }

    private void init(Context context) {
        init(context, null);
    }

    private void init(Context context, OnViewClickListener onViewClickListener) {
        init(context, onViewClickListener, true);
    }

    private void init(Context context, OnViewClickListener onViewClickListener, boolean showRemainingAtt) {
        flexiImgDao = DaoManager.getInstance().getDaoSession().getFlexiImgDao();
        setOrientation(VERTICAL);
        mOnViewClickListener = onViewClickListener;
        mContext = context;
        mShowRemainingAtt = showRemainingAtt;
        removeAllViews();
    }

    public void setOnClickListener(OnViewClickListener onViewClickListener) {
        mOnViewClickListener = onViewClickListener;
    }

    public int getConversationId() {
        return mConversationId;
    }

    public void setConversationId(int mConversationId) {
        this.mConversationId = mConversationId;
    }

    public void setQuoteViewId(int quoteViewId) {
        this.mQuoteViewId = quoteViewId;
    }

    public interface OnViewClickListener {
        void onImgClick(ImageView imageView);
        void onAttClick(Attachment attachment);
        void onQuoteButtonClick(View view, boolean collapsed);
    }

    private String pattern_span(String text) {
        return text.replaceAll("(?i)<span[^>]+>", "<span>");
    }

    private String pattern_p(String text, int type) {
        //text.replaceAll("(?i)<p[^>]+>", "\r\n<p>");
        //text = text.replaceAll("(?i)<p[^>]+>", "<p>");
        if(pt_p == null) {
            pt_p = Pattern.compile("(?i)<p[^>]+>");
        }
        mt_p = pt_p.matcher(text);

        StringBuffer sb = new StringBuffer();
        int p_end = 0;
        while(mt_p.find()){
            String align = "left";
            String text_indent = "0";
            int p_start = mt_p.start();
            p_end = mt_p.end();
            String p_group = mt_p.group();
            int align_start = p_group.indexOf("text-align:");
            if(align_start > 0) {
                String align_end = p_group.substring(align_start);
                if(align_end.contains("center")) {
                    align = "center";
                } else if(align_end.contains("right")) {
                    align = "right";
                }
            }
            int text_indent_start = p_group.indexOf("text-indent:");
            if(text_indent_start > 0) {
                int text_indent_end = p_group.indexOf("rem", text_indent_start + 12);
                if(text_indent_end > 0 && text_indent_end > text_indent_start) {
                    text_indent = p_group.substring(text_indent_start + 12, text_indent_end);
                } else {
                    text_indent_end = p_group.indexOf("em", text_indent_start + 12);
                    if(text_indent_end > 0 && text_indent_end > text_indent_start) {
                        text_indent = p_group.substring(text_indent_start + 12, text_indent_end);
                    }
                }
            }

            String new_tag = "<p style=\"text-align:" + align + ";text-indent:" + text_indent+ "\">";
            mt_p.appendReplacement(sb, new_tag);
            //Log.i(TAG, "P标签 buffer::  " + sb.toString());
        }
        text = sb.toString() + text.substring(p_end);

        //String ttt = "<p></p><p></p rn_num=\"3\"><p></p>";
        if(pt_p_rn == null) {
            pt_p_rn = Pattern.compile("(?i)</p[^>]*>");
            //pt_p_rn = Pattern.compile("(?i)</p\\s*>");
        }
        if(type == ENTER_TEXT_TYPE_HAVETABLE_CELL) {
            text = FormatUtil.format_p_rnNum(text, 0);//设置表格最后一个<\p>的换行符的个数
        }
        mt_p_rn = pt_p_rn.matcher(text);
        StringBuffer rn_sb = new StringBuffer();
        int rn_p_end = 0;
        while (mt_p_rn.find()) {
            String rn_num = "2";
            if(type == ENTER_TEXT_TYPE_FIRST || type == ENTER_TEXT_TYPE_HAVETABLE_FIRST) {
                rn_num = "2";
            } else {
                rn_num = "1";
            }
            int rn_p_start = mt_p_rn.start();
            rn_p_end = mt_p_rn.end();
            String rn_p_group = mt_p_rn.group();
            int rn_num_start = rn_p_group.indexOf("rn_num=\"");
            if(rn_num_start > 0) {
                int rn_num_end = rn_p_group.indexOf("\"", rn_num_start + 8);
                if(rn_num_end > 0 && rn_num_end > rn_num_start) {
                    rn_num = rn_p_group.substring(rn_num_start + 8, rn_num_end);
                }
            }
            String new_tag = "</p>";
            try{
                int num = Integer.parseInt(rn_num);
                for(int i = 0; i < num; i++) {
                    new_tag += "\r\n";
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
            mt_p_rn.appendReplacement(rn_sb, new_tag);
            //Log.i(TAG, "");
        }
        text = rn_sb.toString() + text.substring(rn_p_end);


        //text = text.replaceAll("(?i)</p>", "</p>\r\n\r\n");
        //Log.i(TAG, "P标签 text = " + text);
        //text = text.replaceAll("(?i)<p[^>]+>", "<p style=\"text-align:" + align + ";text-indent:" + text_indent+ "\">");
        return text;
    }

    private String pattern_common(String text) {
        text = text.replaceAll("<i\\s*?>", "<i>");
        text = text.replaceAll("<b\\s*?>", "<b>");
        text = text.replaceAll("<u\\s*?>", "<u>");
        text = text.replaceAll("<z\\s*?>", "<z>");
        text = text.replaceAll("<sup\\s*?>", "<sup>");
        text = text.replaceAll("<sub\\s*?>", "<sub>");
        text = text.replaceAll("<wav\\s*?>", "<wav>");
        text = text.replaceAll("<span\\s*?>", "<span>");
        text = text.replaceAll("<em\\s*?>", "<i>");
        text = text.replaceAll("</em>", "</i>");

        text = text.replaceAll("\u00AD", "");
        text = text.replaceAll("\uDBC0\uDDB3", "’");
        text = text.replaceAll("\uDBC3\uDCEB", "□");

        text = text.replaceAll("&there4;", "∴");
        text = text.replaceAll("&amp;nbsp;", " ");
        text = text.replaceAll("&nbsp;", " ");
        text = text.replaceAll("&amp;quot;", "\"");
        text = text.replaceAll("&quot;", "\"");
        text = text.replaceAll("&amp;amp;", "&");
        text = text.replaceAll("&amp;", "&");
        text = text.replaceAll("&amp;lt;", "<");
        text = text.replaceAll("&lt;", "<");
        text = text.replaceAll("&amp;le;", "<=");
        text = text.replaceAll("&le;", "<=");
        text = text.replaceAll("&amp;gt;", ">");
        text = text.replaceAll("&gt;", ">");
        text = text.replaceAll("&amp;ge;", ">=");
        text = text.replaceAll("&ge;", ">=");
        text = text.replaceAll("&amp;apos;", "'");
        text = text.replaceAll("&apos;", "'");

        text = text.replaceAll("<seg>(.+?)</seg>", "<span>$1</span>");

        //String value = Html.fromHtml(thisToken().value.toString()).toString();
        text = text.replaceAll("(&[#a-zA-z0-9]{2,8};)", "<escape>$1</escape>");


        return text;
    }
    private String pattern_svg(String text) {
        if(pt_svg == null) {
            pt_svg = Pattern.compile("(?i)<img[^>]+?src=\"data:image/svg\\+xml;charset=utf8,[\\s\\S]*?/>");
        }
        mt_svg = pt_svg.matcher(text);
        StringBuffer sb = new StringBuffer();
        int end = 0;
        while(mt_svg.find()) {
            int start = mt_svg.start();
            end = mt_svg.end();
            String group = mt_svg.group();
            int src_start = group.indexOf("src=\"");
            int src_end = group.indexOf("\"", src_start + 5);
            String src = group.substring(src_start + 5, src_end);
            /*try {
                src = URLDecoder.decode(src, "utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }*/

            String new_tag = "";
            new_tag += "<svgsharp>" + src + "</svgsharp>";
            mt_svg.appendReplacement(sb, new_tag);
        }
        text = sb.toString() + text.substring(end);
        return text;
    }
    private String pattern_base64(String text) {
        if(pt_base64 == null) {
            pt_base64 = Pattern.compile("(?i)<img\\s+src=\"data:image/jpeg;base64[^>]+/>");
        }
        mt_base64 = pt_base64.matcher(text);
        StringBuffer sb = new StringBuffer();
        int end = 0;
        while(mt_base64.find()) {
            int start = mt_base64.start();
            end = mt_base64.end();
            String group = mt_base64.group();
            int src_start = group.indexOf("src=\"");
            int src_end = group.indexOf("\"", src_start + 5);
            String src = group.substring(src_start + 5, src_end);
            String new_tag = "";
            new_tag += "<base64 data=\"" + src + "\"> " + "</base64>";
            mt_base64.appendReplacement(sb, new_tag);
        }
        text = sb.toString() + text.substring(end);
        return text;
    }

    private String pattern_img(String text) {
        //Pattern p = Pattern.compile("(?i)<img\\s+[^>]+/>");
        if(pt_img == null) {
            pt_img = Pattern.compile("(?i)<img\\s+.+?/?>");
        }
        mt_img = pt_img.matcher(text);
        StringBuffer sb = new StringBuffer();
        int end = 0;
        while(mt_img.find()){
            int start = mt_img.start();
            end = mt_img.end();
            String group = mt_img.group();
            //Log.i(TAG, "图片 start = " + start + ", end = " + end + ", group =" + group);
            int src_start = group.indexOf("src=\"");
            int src_end = group.indexOf("\"", src_start + 5);
            String src = group.substring(src_start + 5, src_end);
            //Log.i(TAG, "图片 src = " + src);
            String width = null;
            String height = null;
            boolean b_width_pt = false;
            boolean b_height_pt = false;
            int style_start = group.indexOf("style=\"");
            if(style_start > 0) {
                int style_end = group.indexOf("\"", style_start + 7);
                if(style_end > 0 && style_end > style_start) {
                    String style = group.substring(style_start + 7, style_end);
                    //Log.i(TAG, "图片 style = " + style);
                    int width_start= style.indexOf("width:");
                    if(width_start >= 0) {
                        int width_end = 0;
                        int width_end_px = style.indexOf("px", width_start + 6);
                        int width_end_pt = style.indexOf("pt", width_start + 6);
                        if(width_end_px > 0 && width_end_pt > 0) {
                            width_end = width_end_px > width_end_pt ? width_end_pt : width_end_px;
                            b_width_pt = width_end_px > width_end_pt ? true : false;
                        } else if (width_end_px > 0) {
                            width_end = width_end_px;
                        } else if(width_end_pt > 0) {
                            width_end = width_end_pt;
                            b_width_pt = true;
                        }
                        if(width_end > 0 && width_end > width_start) {
                            width = style.substring(width_start + 6, width_end).trim();
                            //Log.i(TAG, "图片 width = " + width);
                        }
                    }
                    int height_start= style.indexOf("height:");
                    if(height_start >= 0) {
                        int height_end = 0;
                        int height_end_px = style.indexOf("px", height_start + 7);
                        int height_end_pt = style.indexOf("pt", height_start + 7);
                        if(height_end_px > 0 && height_end_pt > 0) {
                            height_end = height_end_px > height_end_pt ? height_end_pt  : height_end_px;
                            b_height_pt = height_end_px > height_end_pt ? true  : false;
                        } else if (height_end_px > 0) {
                            height_end = height_end_px;
                        } else if(height_end_pt > 0) {
                            height_end = height_end_pt;
                            b_height_pt = true;
                        }
                        if(height_end > 0 && height_end > height_start) {
                            height = style.substring(height_start + 7, height_end).trim();
                            //Log.i(TAG, "图片 height = " + height);
                        }
                    }
                }
            }
            /*String new_tag = "<img src=\"" +src + "\"";
            if(width != null) {
                new_tag += " w=\"" + width + "\"";
            }
            if(height != null) {
                new_tag += " h=\"" + height +"\"";
            }
            new_tag += "/>";*/
            String new_tag = "";
            if(width != null && height != null) {
                int i_width = 0;
                int i_height = 0;
                try{
                    i_width = (int)Float.parseFloat(width);
                    i_height = (int)Float.parseFloat(height);
                    if(b_height_pt) {
                        i_height = i_height * MyConfige.pt_to_px_scale;
                    }
                    if(b_width_pt) {
                        i_width = i_width * MyConfige.pt_to_px_scale;
                    }
                    if(i_width > i_height && i_height < 20) {
                        i_height = i_width;
                    }
                }catch (Exception e) {
                    e.printStackTrace();
                }
                new_tag += "<img src_ywyh=\"" +src + "\"";
                new_tag += " w=\"" + i_width + "\"";
                new_tag += " h=\"" + i_height +"\"";
            } else if(width != null) {
                int i_width = 0;
                try{
                    i_width = (int)Float.parseFloat(width);
                    if(b_width_pt) {
                        i_width = i_width * MyConfige.pt_to_px_scale;
                    }
                }catch (Exception e) {
                    e.printStackTrace();
                }
                new_tag += "<img src_ywnh=\"" +src + "\"";
                new_tag += " w=\"" + i_width + "\"";
            } else if(height != null) {
                int i_height = 0;
                try{
                    i_height = (int)Float.parseFloat(height);
                    if(b_height_pt) {
                        i_height = i_height * MyConfige.pt_to_px_scale;
                    }
                }catch (Exception e) {
                    e.printStackTrace();
                }
                new_tag += "<img src_nwyh=\"" +src + "\"";
                new_tag += " h=\"" + i_height +"\"";
            } else {
                new_tag += "<img src_nwnh=\"" +src + "\"";
            }
            new_tag += "/>";
            mt_img.appendReplacement(sb, new_tag);
            //Log.i(TAG, "图片 buffer::  " + sb.toString());
            //text.substring(0, start) + "<img src=\"" +src + "\"" + "/>" +
        }
        text = sb.toString() + text.substring(end);
        //Log.i(TAG, "图片最终 text = " + text);

        // text = text.replaceAll("(?i)<img\\s+src=\"http")
        // <img src="http://newpage-edu.oss-cn-beijing.aliyuncs.com/58eed61df8db4ac8a5a81ac1781a9de5.jpg" style="null" />
        return text;
    }

    private int get_table_td_group_count(String text) {
        if(pt_td_group_count == null) {
            pt_td_group_count = Pattern.compile("<td.*?>[\\s\\S]*?</td>");
        }
        mt_td_group_count = pt_td_group_count.matcher(text);
        int count = 0;
        while(mt_td_group_count.find()) {
            count++;
        }
        return count;
    }
    private String ifHaveTableDelete(String text) {
        if(pt_ifHaveTableDelete == null) {
            pt_ifHaveTableDelete = Pattern.compile("<table.*?>[\\s\\S]*?</table>");
        }
        mt_ifHaveTableDelete = pt_ifHaveTableDelete.matcher(text);
        String text_temp = "";
        int end = 0;
        while(mt_ifHaveTableDelete.find()) {
            if(!isHaveTable && !isHaveImg) {
                isHaveTable = true;
                text_deleteTable_pre = text;
                td_group_count = get_table_td_group_count(text);
                Log.i(TAG, "单元格的个数：td_group_count = " + td_group_count);
            }
            int start = mt_ifHaveTableDelete.start();
            text_temp += text.substring(end, start);
            end = mt_ifHaveTableDelete.end();
            String group = mt_ifHaveTableDelete.group();
        }
        text_temp += text.substring(end);
        return text_temp;
    }

    private String ifFirstDeleteImg(String text) {
        if(pt_ifFirstDeleteImg == null) {
            pt_ifFirstDeleteImg = Pattern.compile("(?i)<img\\s+.+?/?>");
        }
        mt_ifFirstDeleteImg = pt_ifFirstDeleteImg.matcher(text);
        String text_temp = "";
        int end = 0;
        while(mt_ifFirstDeleteImg.find()) {
            isHaveImg = true;
            int start = mt_ifFirstDeleteImg.start();
            text_temp += text.substring(end, start);
            end = mt_ifFirstDeleteImg.end();
            String group = mt_ifFirstDeleteImg.group();
        }
        text_temp += text.substring(end);
        return text_temp;
    }

    private String pattern_table(String text) {
        //为了去掉换行符
        if(pt_table_2 == null) {
            pt_table_2 = Pattern.compile("<table.*?>[\\s\\S]*?</table>");
        }
        mt_table_2 = pt_table_2.matcher(text);
        String text_temp = "";
        int end = 0;
        while(mt_table_2.find()){
            int start = mt_table_2.start();
            text_temp += text.substring(end, start);
            end = mt_table_2.end();
            String group = mt_table_2.group();
            //m.appendReplacement(sb, empt); //不能使用这个，他会将$和转译符也自动去掉
            Pattern rn_p = Pattern.compile("\r\n");
            Matcher rn_m = rn_p.matcher(group);
            int rn_end = 0;
            while(rn_m.find()){
                int rn_start = rn_m.start();
                text_temp += group.substring(rn_end, rn_start);
                rn_end = rn_m.end();
                String rn_group = rn_m.group();
            }
            text_temp += group.substring(rn_end);

        }
        text_temp += text.substring(end);
        return text_temp;
    }
    private String pattern_latex(String text) {
        text = text.replaceAll("<latex>\\$\\$", "\\$\\$ \\\\Large ");
        //text = text.replaceAll("<latex>\\$\\$", "\\$\\$ ");
        text = text.replaceAll("\\$\\$</latex>", "\\$\\$");
        text = text.replaceAll("<latex>", "\\$\\$ \\\\Large ");
        //text = text.replaceAll("<latex>", "\\$\\$ ");
        text = text.replaceAll("</latex>", "\\$\\$");
        text = text.replaceAll("　", "  "); //将不是标准的空格转为标准空格 2020-05-07
        text = pattern_latex_zh_2(text);
        return text;
    }

    private String pattern_latex_zh(String text) {
        text = text.replaceAll("（", "(");
        text = text.replaceAll("）", ")");
        text = text.replaceAll("，", ",");
        text = text.replaceAll("－", "-");
        text = text.replaceAll("：", ":");
        text = text.replaceAll("∆", "Δ");
        //text = text.replaceAll("、", "");
        text = text.replaceAll("\\{\\\\int\\s*?\\}_", "\\\\int_");
        text = text.replaceAll("\\\\mathrm\\{\\\\text\\{'\\}\\}", "'");
        return text;
    }
    private String pattern_latex_zh_2(String text) {
        if(pt_latex_zh_2 == null) {
            pt_latex_zh_2 = Pattern.compile("(?i)\\$\\$[\\s\\S]*?\\$\\$");
        }
        mt_latex_zh_2 = pt_latex_zh_2.matcher(text);
        String text_temp = "";
        int end = 0;
        while(mt_latex_zh_2.find()) {
            int start = mt_latex_zh_2.start();
            text_temp += text.substring(end, start);
            end = mt_latex_zh_2.end();
            String group = mt_latex_zh_2.group();
            String zh_3 = pattern_latex_zh_3(group);
            text_temp += zh_3;
        }
        text_temp += text.substring(end);
        return text_temp;
    }
    private String pattern_latex_zh_3(String text) {
        text = pattern_latex_zh(text);

        if(pt_latex_zh_3 == null) {
            pt_latex_zh_3 = Pattern.compile("(?i)[、\\u4e00-\\u9fa5]+");
        }
        mt_latex_zh_3 = pt_latex_zh_3.matcher(text);
        String text_temp = "";
        int end = 0;
        while(mt_latex_zh_3.find()) {
            int start = mt_latex_zh_3.start();
            text_temp += text.substring(end, start);
            end = mt_latex_zh_3.end();
            String group = mt_latex_zh_3.group();

            text_temp = text_temp + " \\tiny " + group + " \\Large ";
        }
        text_temp += text.substring(end);
        return text_temp;

    }

    private String pattern_en_unline_num(String text) {
        if(text == null) {
            return "";
        }
        String back_text = "";
        do{
            back_text = text;
            en_unline_num++;
            text = text.replaceFirst("#num#", "<u> " + en_unline_num + " </u>");
        }while (!back_text.equals(text));
        return text;
    }

    private void second_line_img(String text) {
        text = pattern_base64(text);
        line_img_find_src(text);
    }

    private void line_img_find_src(String text) {
        //Pattern p = Pattern.compile("(?i)<img\\s+[^>]+/>");
        if(pt_line_img_find_src == null) {
            pt_line_img_find_src = Pattern.compile("(?i)<img\\s+.+?/?>");
        }
        mt_line_img_find_src = pt_line_img_find_src.matcher(text);
        int end = 0;
        while(mt_line_img_find_src.find()) {
            int start = mt_line_img_find_src.start();
            end = mt_line_img_find_src.end();
            String group = mt_line_img_find_src.group();
            int src_start = group.indexOf("src=\"");
            int src_end = group.indexOf("\"", src_start + 5);
            String src = group.substring(src_start + 5, src_end);

            boolean isPt = false;
            int style_start = group.indexOf("style=\"");
            if(style_start > 0) {
                int style_end = group.indexOf("\"", style_start + 7);
                if(style_end > 0 && style_end > style_start) {
                    String style = group.substring(style_start + 7, style_end);
                    int ptIndex = style.indexOf("pt");
                    if(ptIndex > 0){
                        isPt = true;
                    }
                }
            }


            img_glede(src, text, isPt);
            break;
        }
        if(end == 0) {
            //全部替换完毕
            //Log.i(TAG, "试题图片-全部替换完毕：" + text);
            setText(text);

        }
    }

    private void img_glede(String url, final String text, final boolean isPt) {
        int flexId = 0;
        if(flexibleRichIdArr.size() > 0) {
            flexId = flexibleRichIdArr.get(flexibleRichIdArr.size() - 1);
        }
        final int f_flexId = flexId;

        //数据库离线，已关闭
        FlexiImg fg = null;
        if(url != null && flexiImgDao != null && MyConfige.isDbImg) {
            try{
                fg = flexiImgDao.queryBuilder().where(FlexiImgDao.Properties.Url.eq(url)).unique();
                if(fg != null) {
                    line_img_pattern_src(fg.getImgBase64(), text);
                    return;
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }

        //文件离线
        String filePath = "";
        String type = "";
        if(MyConfige.isDownImg) {
            if(url != null && (url.startsWith("http:") || url.startsWith("https:"))) {
                String dirPath = getContext().getExternalFilesDir(null).getAbsolutePath();
                dirPath += File.separator + "flex";

                File dirFile = new File(dirPath);
                if (!dirFile.exists()) {
                    boolean mkdirs = dirFile.mkdirs();
                    if (!mkdirs) {
                        Log.i(TAG, "创建失败：" + mkdirs);
                    } else {
                        Log.i(TAG, "创建成功");
                    }
                }
                //url名字有特殊字符或者太长不符合android文件名字
                String fileName = MD5.getMD5(url);
                if ("PNG".equals(url.substring(url.lastIndexOf(".") + 1).toUpperCase())) {
                    type = ".png";
                } else {
                    type = ".jpg";
                }
                filePath = dirPath + File.separator + fileName + type;
            } else {
                filePath = url;
            }
            File f = new File(filePath);
            if (f.exists()) {
                url = filePath;
            } else {
                if (!Utils.isNetworkAvailable(mContext)) {
                    line_img_pattern_src("", text);
                    return;
                }
            }

        } else {
            if (!Utils.isNetworkAvailable(mContext)) {
                line_img_pattern_src("", text);
                return;
            }
        }


        final String url_2 = url;
        final String filePath_2 = filePath;
        final FlexiImg fg_2 = fg;
        final String type_2 = type;
        //加载本地资源文件
        if(FormatUtil.isInteger(url)) {
            Glide.with(mContext)
                    .load(Integer.parseInt(url))
                    .asBitmap().into(new SimpleTarget<Bitmap>() {
                @Override
                public void onResourceReady(final Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
                    img_to_db(url_2, f_flexId, resource, isPt, text, fg_2, filePath_2, type_2);
                }

                @Override
                public void onLoadFailed(Exception e, Drawable errorDrawable) {
                    super.onLoadFailed(e, errorDrawable);
                    Log.i(TAG, "试题图片-失败2 url = " + url_2);
                    if(flexibleRichIdArr.contains(f_flexId)) {
                        line_img_pattern_src("", text);
                    }
                }
            });
        } else {
            Glide.with(mContext).load(url).asBitmap().into(new SimpleTarget<Bitmap>() {
                @Override
                public void onResourceReady(final Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
                    img_to_db(url_2, f_flexId, resource, isPt, text, fg_2, filePath_2, type_2);
                }

                @Override
                public void onLoadFailed(Exception e, Drawable errorDrawable) {
                    super.onLoadFailed(e, errorDrawable);
                    Log.i(TAG, "试题图片-失败1 url = " + url_2);
                    if(flexibleRichIdArr.contains(f_flexId)) {
                        line_img_pattern_src("", text);
                    }
                }
            });
        }
    }

    private void img_to_db(final String url, final int f_flexId, final Bitmap resource, final boolean isPt, final String text, final FlexiImg fg, final String filePath, final String type) {
        //Log.i(TAG, "试题图片-成功：" + str_base64);

        int g_w_0 = this.getWidth();
        DisplayMetrics dm = getResources().getDisplayMetrics();
        if(g_w_0 > 0.5 * dm.widthPixels) {
        } else {
            g_w_0 = dm.widthPixels;
        }
        final int g_w = g_w_0;

        if(flexibleRichIdArr.contains(f_flexId)) {
            GeekThreadPools.executeWithGeekThreadPool(new Runnable() {
                @Override
                public void run() {
                    if(isKill) {
                        return;
                    }

                    Bitmap resource_2 = transparent_2_white_JPG(resource);
                    if(MyConfige.isDownImg) {
                        if(filePath != null && !filePath.equals(url)) {
                            saveBitmap(resource_2, filePath, type);
                        }
                    }
                    //图片打印屏幕的宽，会显示不了
                    int b_w = resource_2.getWidth();
                    int b_h = resource_2.getHeight();
                    float sc = 1.0f;
                    if (isPt) {
                        sc = 2;
                        b_w = (int)sc * b_w;
                    }

                    if(b_w > 0.9 * g_w) {
                        if(isPt) {
                            sc = 2.0f * 0.9f * g_w / b_w;
                        } else {
                            sc = 1.0f * 0.9f * g_w / b_w;
                        }
                    }
                    if(b_h * sc < 25) {
                        sc *= 1.1;
                    }

                    String str_base64 = null;

                    /*if (isPt) {
                        str_base64 = Base64Util.bitmapToBase64(resource_2, 2, 2);
                    } else {
                        str_base64 = Base64Util.bitmapToBase64(resource_2);
                    }*/
                    str_base64 = Base64Util.bitmapToBase64(resource_2, sc, sc);

                    if(mContext != null && mContext instanceof Activity && flexibleRichIdArr.contains(f_flexId)) {
                        final String str_base64_2 = str_base64;
                        ((Activity)mContext).runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                if(isKill) {
                                    return;
                                }
                                if(url != null && str_base64_2 != null && fg == null && flexiImgDao != null &&  MyConfige.isDbImg) {
                                    try{
                                        FlexiImg flexiImg = new FlexiImg(null, url, str_base64_2);
                                        flexiImgDao.insertOrReplace(flexiImg);
                                    }catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                }
                                line_img_pattern_src(str_base64_2, text);
                            }
                        });
                    }
                }
            });
        }
    }

    /** 保存方法 */
    public void saveBitmap(Bitmap bitmap, String filePath, String type) {
        File f = new File(filePath);
        if (f.exists()) {
            return;
        }
        try {
            FileOutputStream out = new FileOutputStream(f);
            if(".png".equals(type)) {
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
            } else {
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
            }

            out.flush();
            out.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public  Bitmap transparent_2_white_JPG(Bitmap bitmap) {
        //复制Bitmap  因为png可以为透明，jpg不支持透明，把透明底明变成白色

        //主要是先创建一张白色图片，然后把原来的绘制至上去
        Bitmap outB=bitmap.copy(Bitmap.Config.ARGB_8888,true);
        Canvas canvas=new Canvas(outB);
        canvas.drawColor(Color.WHITE);
        canvas.drawBitmap(bitmap, 0, 0, null);
        return outB;
    }

    private void line_img_pattern_src(String str_base64, String text) {
        //Pattern p = Pattern.compile("(?i)<img\\s+[^>]+/>");
        if(pt_line_img_pattern_src == null) {
            pt_line_img_pattern_src = Pattern.compile("(?i)<img\\s+.+?/?>");
        }
        mt_line_img_pattern_src = pt_line_img_pattern_src.matcher(text);
        StringBuffer sb = new StringBuffer();
        int end = 0;
        while(mt_line_img_pattern_src.find()) {
            int start = mt_line_img_pattern_src.start();
            end = mt_line_img_pattern_src.end();
            String group = mt_line_img_pattern_src.group();
            int src_start = group.indexOf("src=\"");
            int src_end = group.indexOf("\"", src_start + 5);
            String src = group.substring(src_start + 5, src_end);
            String new_tag = "";
            if(str_base64 != null && str_base64.length() > 1) {
                new_tag += "<base64 data=\"" + str_base64 + "\"> " + "</base64>";
            }
            mt_line_img_pattern_src.appendReplacement(sb, new_tag);
            break;
        }
        text = sb.toString() + text.substring(end);
        line_img_find_src(text);
    }


    //第一步 定义接口
    public interface OnFlexibleListener {
        void onComplete(FlexibleRichTextView view);
    }
    private OnFlexibleListener listener;
    //第二步， 写一个公共的方法
    public void setOnFlexibleListenerr(OnFlexibleListener listener) {
        this.listener = listener;
    }
}
